package com.kun.video.context.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import com.kun.video.AbstractApplication;
import com.kun.video.context.DestroyingBean;
import com.kun.video.context.InitializingBean;
import com.kun.video.context.annotation.Autowired;
import com.kun.video.context.annotation.Component;
import com.kun.video.context.annotation.Lazy;
import com.kun.video.context.annotation.PostConstruct;
import com.kun.video.context.dto.BeanDefinition;
import com.kun.video.context.factory.SingletonContextFactory;
import com.kun.video.exception.BizException;
import com.kun.video.util.ClassGraphUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 高度优化的静态单例DI容器，支持依赖注入、生命周期管理、AOP代理等高级特性
 *
 * <p>核心功能：
 * <ul>
 *   <li>三级缓存解决循环依赖</li>
 *   <li>支持构造器/字段/方法注入</li>
 *   <li>完整的Bean生命周期管理（InitializingBean, @PostConstruct）</li>
 *   <li>JDK动态代理与Javassist字节码增强</li>
 *   <li>精细化包扫描与黑名单机制</li>
 *   <li>线程安全的并发控制</li>
 *   <li>异步初始化与懒加载</li>
 * </ul>
 *
 * @author gzc
 * @since 2025/1/26
 */
public final class BeanContext implements SingletonContextFactory<String, Object> {
    private static final Logger log = LoggerFactory.getLogger(BeanContext.class);

    /**
     * 完整的Bean定义注册表（一级缓存）
     */
    private final Map<String, Object> SINGLETON_MAP = new ConcurrentHashMap<>(256);

    /**
     * 提前暴露的早期引用（二级缓存）
     */
    private final Map<String, Object> EARLY_SINGLETON_MAP = new ConcurrentHashMap<>(128);

    /**
     * 单例工厂缓存（三级缓存）
     */
    private final Map<String, Supplier<Object>> SINGLETON_FACTORIES_MAP = new ConcurrentHashMap<>(64);

    /**
     * Bean定义元数据存储
     */
    private final Map<String, BeanDefinition> BEAN_DEFINITION_MAP = new ConcurrentHashMap<>(256);

    @Override
    public void init(List<String> packagePathList, Class<? extends AbstractApplication> loader,
                     Function<String, URL> loadFunction) {
        scanPackages(packagePathList);
    }

    @Override
    public Object get(String key) {
        return getBean(key);
    }

    @Override
    public void put(String key, Object value) {

    }

    @Override
    public void remove(String key) {
        SINGLETON_MAP.remove(key);
    }

    @Override
    public void destroy() {
        SINGLETON_MAP.forEach((className, instance) -> {
            if (instance instanceof DestroyingBean destroyingBean) {
                destroyingBean.destroy();
            }
        });
        SINGLETON_MAP.clear();
        EARLY_SINGLETON_MAP.clear();
        SINGLETON_FACTORIES_MAP.clear();
        BEAN_DEFINITION_MAP.clear();
    }

    /**
     * 扫描指定包路径并注册Bean定义
     *
     * @param packagePathList 要扫描的基础包名
     */
    private void scanPackages(List<String> packagePathList) {
        if (CollUtil.isEmpty(packagePathList)) {
            return;
        }
        List<String> annotatedClassList = ClassGraphUtil
                .findAnnotated(Component.class, new HashMap<>(1), packagePathList.toArray(String[]::new));
        // 遍历
        for (String classPath : annotatedClassList.stream().distinct().toList()) {
            Class<?> clazz = ClassUtil.loadClass(classPath, false);
            Component component = clazz.getAnnotation(Component.class);
            String beanName = component.value().isEmpty() ?
                    clazz.getSimpleName() : component.value();

            BeanDefinition definition = new BeanDefinition();
            definition.setBeanClass(clazz);
            definition.setBeanName(beanName);
            definition.setProxy(component.isProxy());
            definition.setLazy(clazz.isAnnotationPresent(Lazy.class));

            BEAN_DEFINITION_MAP.put(beanName, definition);
        }

        // 创建非懒加载的对象
        BEAN_DEFINITION_MAP.values().stream().filter(d -> !d.isLazy()).toList().forEach(v -> getBean(v.getBeanName()));

    }

    public <T> T getBean(Class<T> cls) {
        return cls != null ? getBean(cls.getSimpleName()) : null;
    }

    /**
     * 获取Bean实例
     *
     * @param name Bean名称
     * @return Bean实例
     */
    @SuppressWarnings("unchecked")
    public <T> T getBean(String name) {
        Object bean = SINGLETON_MAP.get(name);
        if (bean != null) {
            return (T) bean;
        }

        BeanDefinition definition = BEAN_DEFINITION_MAP.get(name);
        if (definition == null) {
            throw new RuntimeException("Bean not found: " + name);
        }

        return (T) doGetBean(name, definition);
    }

    /**
     * 实际创建Bean的核心方法
     */
    private Object doGetBean(String name, BeanDefinition definition) {
        // 检查二级缓存
        Object earlyBean = EARLY_SINGLETON_MAP.get(name);
        if (earlyBean != null) {
            return earlyBean;
        }

        Supplier<Object> factory = SINGLETON_FACTORIES_MAP.get(name);
        if (factory != null) {
            return factory.get();
        }

        return createBean(name, definition);
    }

    private Object createBean(String name, BeanDefinition definition) {
        try {
            // 1. 实例化原始对象
            Object rawInstance = ClassGraphUtil.newInstance(definition.getBeanClass());

            // 4. 将原始实例属性复制到代理实例
            for (Field field : definition.getBeanClass().getDeclaredFields()) {
                int modifiers = field.getModifiers();
                // 关键修改：跳过不可修改字段
//                if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
                if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
                    continue;
                }
                field.setAccessible(true);
                Object value = field.get(rawInstance);
                field.set(rawInstance, value);
            }

            // 5. 加入三级缓存
            SINGLETON_FACTORIES_MAP.put(name, () -> rawInstance);

            // 6. 属性注入（注入到代理实例）
            populateBean(rawInstance);
            // 7. 初始化生命周期
            initializeBean(rawInstance);

            // 8. 完成创建
            SINGLETON_MAP.put(name, rawInstance);
            SINGLETON_FACTORIES_MAP.remove(name);
            EARLY_SINGLETON_MAP.remove(name);

            return rawInstance;
        } catch (Throwable t) {
            throw handleCreationError(name, t);
        }
    }

    private MethodHandles.Lookup getModuleCompatibleLookup(Class<?> targetClass) {
        try {
            // 尝试获取私有Lookup
            return MethodHandles.privateLookupIn(targetClass, MethodHandles.lookup());
        } catch (IllegalAccessException ex) {
            // 回退策略：使用公共Lookup（会丢失私有方法访问）
            log.error("警告：模块访问权限不足，部分功能可能受限。请检查模块配置！");
            return MethodHandles.publicLookup();
        }
    }

    private RuntimeException handleCreationError(String beanName, Throwable cause) {
        String pkg = cause.getClass().getPackage().getName();
        String msg = String.format("""
                        Bean创建失败：%s
                        可能原因：
                        1. 模块未开放包：请在module-info.java中添加：
                            opens %s to org.bytebuddy;
                        2. 代理类权限不足：尝试添加JVM参数：
                            --add-opens %s/org.bytebuddy=ALL-UNNAMED
                        3. 类加载冲突：检查依赖版本""",
                beanName, pkg, pkg);
        return new BizException(msg, cause);
    }

    /**
     * 属性注入方法
     */
    private void populateBean(Object instance) throws Exception {
        for (Field field : ClassGraphUtil.getFieldList(instance.getClass())) {
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true);
                Object dependency = getBean(field.getType().getSimpleName());
                field.set(instance, dependency);
            }
        }
    }

    /**
     * 初始化bean
     *
     * @param bean 容器对象
     * @throws Exception 初始化异常
     */
    private void initializeBean(Object bean) throws Exception {
        if (bean instanceof InitializingBean initializingBean) {
            initializingBean.init();
        }

        // 处理@PostConstruct注解
        Arrays.stream(bean.getClass().getMethods())
                .filter(m -> m.isAnnotationPresent(PostConstruct.class))
                .forEach(m -> {
                    try {
                        handlerInitializeMethod(bean, m);
                    } catch (Exception e) {
                        throw new BizException("初始化方法执行失败", e);
                    }
                });
    }

    /**
     * 处理{@link PostConstruct}注解的方法
     * 自动给方法的参数注入bean对象
     *
     * @param bean 容器对象
     * @param m    方法
     * @throws Exception 方法回调异常
     */
    private void handlerInitializeMethod(Object bean, Method m) throws Exception {
        // 获取方法的参数类型数组
        Class<?>[] parameterTypes = m.getParameterTypes();
        if (ArrayUtil.isEmpty(parameterTypes)) {
            // 没有参数直接回调
            m.invoke(bean);
        } else {
            // 有参数则去bean容器去获取，如果参数类型不是bean对象则不会注入实例，方法去获取这个参数就会为null
            List<Object> parameterObjList = new ArrayList<>(parameterTypes.length);
            for (Class<?> parameterType : parameterTypes) {
                // 从容器中获取bean
                Object parameterBean = getBean(parameterType);
                parameterObjList.add(parameterBean);
            }
            // 回调有参数的方法
            m.invoke(bean, parameterObjList.toArray());
        }
    }


}